Introduction

Ce projet se concentre sur trois composants électroniques : le capteur d’ultrason, le servomoteur, et le bipeur.

Présentation des composants

Dans cette partie, nous parlerons des composants et nous expliquerons leur fonctionnement.

a) Le capteur d’ultrason

Ci-dessous : un capteur d’ultrason “Module Sonar HC-SR04”

À quoi ça sert ?
Ce module sert principalement à connaître la distance entre un objet et lui-même. Il est très utile pour éviter les collisions des robots autonomes avec leurs environnements.

Fonctionnement :
Comme vous pouvez le voir sur l’image, un capteur d’ultrason ou sonar, possède deux grands cercles grillagés. En fait il l’agit d’un émetteur, et d’un récepteur à ultrason. Pour connaître la distance entre un objet et le sonar, l’émetteur envoie des sons, les sons sont alors propagés dans la direction de l’émission. Lorsque un son percute un objet, un echo est renvoyé vers la source et est alors capté par le récepteur. En faisant une petite opération mathématique, on peut transformer le temps entre l’émission et la réception du signal en distance.

Pour plus d’informations :
le concept d’écholocalisation : https://fr.wikipedia.org/wiki/%C3%89cholocalisation
le sonar : https://fr.wikipedia.org/wiki/Sonar

b) Le servomoteur

Ci-dessous : un servo moteur “Servo motor SG90”

À quoi ça sert ?
Ce module sert principalement à effectuer des rotations précises d’autres objets. En effet, il s’agit d’un moteur ayant la capacité d’effectuer une rotation d’un certain nombre de degrés précis. Ce type de moteur est très utilisé en robotique pour simuler des articulations.

Fonctionnement :
Ce type de moteur existe en plusieurs versions en fonction du couple et du nombre de degrés de rotation. Ce modèle tourne uniquement sur 180° comparé à d’autres qui peuvent effectuer un tour complet, c’est-à-dire 360°. Pour effectuer une rotation précise, le moteur va recevoir un signal compris entre 1 et 2 millisecondes, ou 1 ms correspondra à une rotation de 0°, 1.5 ms de 90° et 2 ms de 180°.

Pour plus d’informations :
le servomoteur : https://fr.wikipedia.org/wiki/Servomoteur

c) Le buzzer

Ci-dessous : un buzzer (ou bipeur en français)

À quoi ça sert ?
Ce module sert à emettre des sons en fonction de la tension reçu. Il peut être utilisé comme alarme, ou boite à musique.

Fonctionnement :
Pour émettre un son, le buzzer a besoin de recevoir une tension particulière, chaque tension correspond à une fréquence de son différente, ainsi nous pouvons varier ces tensions pour produire des sons différents.

Pour plus d’informations :
le bipeur : https://fr.wikipedia.org/wiki/Bipeur

Présentation du projet

Il s’agit d’un sonar rotatif capable de capter les présences et d’émettre une alarme lorsque un objet se trouve à 50 cm ou moins (valeur arbitraire). Ce projet met en oeuvre des compétences en électronique, programmation arduino et python. Nous décomposerons le projet en trois parties distinctes :
1. Le montage électronique
2. Le code arduino
3. Le code python
4. Les résultats

I. Le montage éléctronique

Ci-dessous : le schéma du montage éléctronique

Ce schéma à été réalisé de façon à pouvoir comprendre simplement les branchements.

L’arduino UNO :
L’arduino UNO est la pièce maîtresse du montage, il s’agit du microcontrôleur servant à exécuter le code que l’on va lui insérer. Nous devons donc relier tous les composants à l’arduino pour pouvoir les contrôler. Il faudra relier l’arduino soit par une pile fournissant 5V ou soit par le câble USB (5V).

La breadboard :
La breadboard est une plaque facilitant la mise en place de circuits électriques. Dans ce montage elle est utilisée comme point de convergence des fils + et - des composants, permettant ainsi de fournir en énergie tous les composants (l’arduino UNO ne proposant pas assez d’entrées + et -).

Le sonar :
Les pins trigger et echo sont respectivement reliés aux pins 2 et 4 de l’arduino. Les pins VCC et GRND sont connectés au circuit sur la breadboard.

Le servomoteur :
Les pins VCC et GRND sont connectés au circuit sur la breadboard, tandis que le pin du signal (en jaune) est connecté au pin 7 de l’arduino.

Le buzzer :
le - du buzzer est directement connecté à un deuxième pin GRND de l’arduino, et le + est connecté au pin 6 puisque nous ne voulons pas que le buzzer fonctionne en continu mais qu’il s’active uniquement lors d’un évènement précis (nous verrons cela plus tard).

II. Le code arduino

Une fois le montage réalisé, il faut injecter du code dans notre arduino pour qu’il effectue les actions voulues.

a) variables globales et déclarations

#include <Servo.h>
#include <NewPing.h

Servo radar; //moteur de base
NewPing sonar(2,4,200); // radar tournan

const int PIN_RADAR = 7;
const int PIN_BIP = 6;
const int DISTANCE_MIN = 50;
int distance = 0;

Explications :
Les deux premières lignes servent à inclure les bibliothèques de codes pour le servomoteur et le sonar. Ensuite nous instancions deux objets : le servomoteur (Servo), et le capteur d’ultrasons (NewPing) Nous définissons ensuite les pins du servomoteur et du capteur en suivant notre montage. Enfin, la constante DISATNCE_MIN correspond à la distance à partir de laquelle le buzzer s’activera. la variable distance sera utilisée pour connaître la distance courante.

b) La fonction setup()

void setup() {
  radar.attach(PIN_RADAR);
  pinMode(PIN_BIP,OUTPUT);
  Serial.begin(9600);
}

Explications :
Cette fonction sert à initialiser nos différents objets. Nous initialisons alors notre servomoteur en lui indiquant le pin de signal, et nous affectons le pin du buzzer en tant que sortie. Finalement, nous ouvrons le port de communication (à 9600 bauds), qui sera utilisé pour transmettre des données à notre programme arduino.

c) La fonction getDistance()

int getDistance(){
  delay(70);
  unsigned int uS = sonar.ping();
  int cm = uS/US_ROUNDTRIP_CM;
  return cm;
}

Explications :
Cette fonction sert à convertir le temps démission/réception du sonar en distance en cm. un delai est choisi arbitrairement afin que le module ait le temps de recevoir les informations.

d) La fonction loop()

void loop() {
  for (int i = 0; i < 180; i++){
    distance = getDistance();
    Serial.print(i);
    Serial.print(" ");
    Serial.println(distance);
    if (distance < DISTANCE_MIN && distance != 0){
      digitalWrite(PIN_BIP,HIGH);
      delay(30);
      digitalWrite(PIN_BIP,LOW);
    }
    radar.write(i);
  }
  for (int i = 180; i > 0; i--){
    distance = getDistance();
    Serial.print(i);
    Serial.print(" ");
    Serial.println(distance);
    if (distance < DISTANCE_MIN && distance != 0){
      digitalWrite(PIN_BIP,HIGH);
      delay(30);
      digitalWrite(PIN_BIP,LOW); 
    }
    radar.write(i);
  }
}

Explications :
Voici le coeur de notre programme, il va s’exécuter en boucle. Cette boucle permet au servomoteur de tourner de 0° à 180° tout en laissant le sonar calculer la distance. À chaque distance calculée, les données sont écrites sur le port série. Si le sonar détecte un objet à moins de 50 cm, le buzzer sonne.

III. Le code python

Le code python va servir à lire les données sur le port série et les afficher sur un graphique. Ce code a partielement été repris d’un autre projet de Wojjy72, voici son git https://github.com/Wojjy72.

a) Les imports

import serial
import time
from math import pi
import matplotlib.pyplot as plt
import matplotlib.lines as mlines
import numpy as np
from drawnow import drawnow

b) Création des cercles

Explications :
Nous utiliserons trois librairies importantes :
1. matplotlib permettant de créer des graphiques.
2. drawnow permettant de rafraichir le graphique en temps réel lorsque’une modification est effectuée.
3. serial permettant la lecture et l’écriture sur les ports séries.

data = np.zeros((180, 2)) #create empty array for data
line = np.zeros((2, 2)) #create array for line

fig = plt.figure() #create plot

 #40cm circle
fourx = np.linspace(-40, 40, 25)
foury = np.sqrt(1600 - (fourx * fourx))

#80cm circle
eightx = np.linspace(-80, 80, 50)
eighty = np.sqrt(6400 - (eightx * eightx))

#120cm circle
twox = np.linspace(-120, 120, 75)
twoy = np.sqrt(14400 - (twox * twox))
#160cm circle
sixx = np.linspace(-160, 160, 100)
sixy = np.sqrt(25600 - (sixx * sixx))

Explications : Ces quelques lignes de code servent à initialiser le graphique et à créer les tableaux de données ainsi que les dimensions des cercles de distances.

c) La fonciton redraw()

def redraw():
    #redraw graph
    #resize & rename
    plt.axis((-160, 160, 0, 160))
    plt.axes().set_aspect('equal', 'datalim')
    plt.title('RADAR (cm)')

    #define lines every 40cm
    four = mlines.Line2D([],[],color='#006400', label='40')
    eight = mlines.Line2D([],[],color='#FF8C00', label='80')
    two = mlines.Line2D([],[],color='r', label='120')
    six = mlines.Line2D([],[],color='k', label='160')

    #draw all lines
    x = data[serial_line[0] - 1, 0]
    y = data[serial_line[0] - 1, 1]

    if x < 150 and y < 150:
        liste_points_x.append(x)
        liste_points_y.append(y)

    plt.plot(liste_points_x,liste_points_y,'s',marker='o', markersize=3, color="red")
    #plt.plot(data[:,0], data[:,1], color ='#fc0000')
    plt.plot(line[:,0], line[:,1], color ='#00FC00')
    plt.plot(fourx,foury, color='#006400')
    plt.plot(eightx,eighty, color='#FF8C00')
    plt.plot(twox,twoy, color='r')
    plt.plot(sixx,sixy, color='k')

    #draw legend
    plt.legend(handles=[four, eight, two, six])

Explications : Cette fonction va servir de paramètre à la fonction drawnow() du main permettant de mettre à jour en temps réel notre graphe. Le graph est mis à jour en fonction de la position du servomoteur et de la distance captée par le capteur d’ultrason, lu à partir du port série. Cette fonction va alors dessiner un segment vert suivant la position du sonar (entre 0° et 180°). Elle sera aussi en charge de dessiner les distances captées, par des points rouges sur le graph.

d) Le main()

time.sleep(1) #delay before starting main()
if __name__ == "__main__":

    print("debut")
    port = "COM5"
    liste_points_x = []
    liste_points_y = []
    ser = serial.Serial(port, baudrate = 9600, timeout = 1)
    if ser.isOpen():
        while True:
            serial_line = ser.readline()
            serial_line = serial_line.decode('UTF-8')
            serial_line = serial_line.replace("\r\n","")
            serial_line = serial_line.split() #array of words from string
            serial_line = list(map(int, serial_line)) #string array to int array
            if not len(serial_line) == 2: #if serial data is incorrect
                serial_line = [1, 0]
            #get x co-ord within circle graph
            data[serial_line[0] - 1, 0] = serial_line[1] * np.cos((pi * serial_line[0])/180)
            #get y co-ord within circle graph
            data[serial_line[0] - 1, 1] = serial_line[1] * np.sin((pi * serial_line[0])/180) 
            #get x co-ord within circle graph
            line[0, 0] = 160 * np.cos((pi * serial_line[0])/180)
            #get y co-ord within circle graph
            line[0, 1] = 160 * np.sin((pi * serial_line[0])/180)
            drawnow(redraw) #refresh graph
            if serial_line[0] == 180 or serial_line[0] == 0 :
                liste_points_x = []
                liste_points_y = []
            time.sleep(0.0001)
        ser.close()

Explications : Tout d’abord, notre main va lire les données présente dans le port série (ici COM5) et les stocker dans une liste, nous aurons donc un indice pour la position du servo, et un autre pour la distance captée. une fois les éléments dans la liste, ils sont transformés en x et y proportionnellement aux unités du graph pour l’affichage (une coordonnée pour le servo, et une pour les distances). À la fin d’un parcours (de 0° à 180° ou l’inverse) tous les points captés sont supprimés et le balayage recommence.

IV. Résulats

Fin du rapport, merci d’avoir lu.